package edu.ccut.saturn.component.impl;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import edu.ccut.saturn.component.DatabaseBroker;
import edu.ccut.saturn.component.ILogicContext;
import edu.ccut.saturn.component.IParameter;
import edu.ccut.saturn.component.IParameterContext;
import edu.ccut.saturn.component.impl.mock.MockRequest;
import edu.ccut.saturn.component.impl.mock.MockResponse;
import edu.ccut.saturn.component.utils.TypeValidation;

/**
 * {@link IParameterContext} implementation
 * 
 * @see IParameterContext
 * @author LeslieGu
 * 
 */
public class SaturnParameterContext implements IParameterContext {

	private Throwable exception;

	private List<IParameter> parameters;

	private DatabaseBroker databaseBroker;

	private String transactionType;
	
	private ILogicContext logicContext;

	public SaturnParameterContext() {
		this.parameters = new LinkedList<IParameter>();

		// TODO: all for test, can delete it?
		this.databaseBroker = new DatabaseBroker();
		this.transactionType = null;
	}

	public SaturnParameterContext(String type) {
		this.parameters = new LinkedList<IParameter>();

		// TODO: all for test, can delete it?
		this.databaseBroker = new DatabaseBroker();
		this.transactionType = type;
	}

	public Throwable getException() {
		return exception;
	}

	public void setException(Throwable exception) {
		this.exception = exception;
	}

	public List<IParameter> getParameters() {
		return parameters;
	}

	public IParameter getParameter(int i) {

		if (i < this.parameters.size()) {
			return this.parameters.get(i);
		}
		return null;
	}

	public Object getParameterValue(int i) {
		IParameter parameter = this.getParameter(i);
		if (null == parameter){
			return null;
		}
		return parameter.getValue();
	}

	public void setParameter(int i, Object value) {

		if (i < this.parameters.size()) {
			this.parameters.get(i).setValue(value);
		}
	}

	public void addParameter(Object value, Class<?> valueType) {

		if (valueType != null && valueType.isInstance(value)) {
			this.parameters.add(new SaturnParameter(value, valueType));
			return;
		}

		this.parameters.add(new SaturnParameter(TypeValidation
				.getValidTypeValue(valueType.getName(), value), valueType));
	}

	public DatabaseBroker getDatabaseBroker() {
		return databaseBroker;
	}

	public void setDatabaseBroker(DatabaseBroker databaseBroker) {
		this.databaseBroker = databaseBroker;
	}

	public Connection getConnection() {
		return this.databaseBroker.getConnection();
	}

	public String getTransactionType() {
		return this.transactionType;
	}

	public void setTransactionType(String transactionType) {
		this.transactionType = transactionType;
	}

	public boolean hasConnection() {
		return this.databaseBroker.hasConnection();
	}

	public void setConnection(Connection connection) {
		this.databaseBroker.setConnection(connection);
	}

	public ILogicContext getLogicContext() {
		return logicContext;
	}

	public void setLogicContext(ILogicContext logicContext) {
		this.logicContext = logicContext;
	}

	public Object getLogicContextValue(String key) {
		return this.logicContext.getValue(key);
	}

	public IParameterContext newParameterContext() {
		SaturnParameterContext parameterContext = new SaturnParameterContext();
		
		parameterContext.transactionType = this.transactionType;
		parameterContext.exception = exception;
		
		if (this.parameters != null) {
			parameterContext.parameters = new ArrayList<IParameter>(this.parameters.size());
		
			for (IParameter parameter : this.parameters) {
				if (parameter.getValue() instanceof HttpServletRequest) {
					HttpServletRequest request = (HttpServletRequest)parameter.getValue();
					MockRequest mockRequest = new MockRequest(request);
					parameterContext.parameters.add(new SaturnParameter(mockRequest, mockRequest.getClass()));
				} else if (parameter.getValue() instanceof HttpServletResponse) {
					HttpServletResponse response = (HttpServletResponse)parameter.getValue();
					MockResponse mockResponse = new MockResponse(response);
					parameterContext.parameters.add(new SaturnParameter(mockResponse, mockResponse.getClass()));
				} else {
					parameterContext.parameters.add(new SaturnParameter(parameter));
				}
			}
		}
		
		if (this.logicContext != null) {
			parameterContext.setLogicContext((ILogicContext)this.logicContext.newLogicContext());
		}
		
		return parameterContext;
	}
}
